"""
存储适配器
为权限管理系统提供兼容的存储接口
"""

import json
import os
import time
import struct
from typing import Dict, Any, List, Optional
try:
    from .page_storage_v3 import PageStorageV3, RecordSerializer
except ImportError:
    from page_storage_v3 import PageStorageV3, RecordSerializer

class StorageAdapter:
    """存储适配器，为权限管理系统提供兼容接口"""
    
    def __init__(self, data_dir: str = "data"):
        """初始化存储适配器"""
        self.storage = PageStorageV3(data_dir)
        self.catalog_file = os.path.join(data_dir, "catalog.json")
        self.catalog = self._load_catalog()
        
        # 确保数据目录存在
        os.makedirs(data_dir, exist_ok=True)
    
    def _load_catalog(self) -> Dict[str, Any]:
        """加载系统目录"""
        if os.path.exists(self.catalog_file):
            try:
                with open(self.catalog_file, 'r', encoding='utf-8') as f:
                    return json.load(f)
            except:
                pass
        return {}
    
    def _save_catalog(self):
        """保存系统目录"""
        try:
            with open(self.catalog_file, 'w', encoding='utf-8') as f:
                json.dump(self.catalog, f, indent=2, ensure_ascii=False)
        except Exception as e:
            print(f"保存系统目录失败: {e}")
    
    def table_exists(self, table_name: str) -> bool:
        """检查表是否存在"""
        return table_name in self.catalog
    
    def create_table(self, table_name: str, schema: Dict[str, Any]):
        """创建表"""
        if table_name in self.catalog:
            raise ValueError(f"表 '{table_name}' 已存在")
        
        # 创建表结构
        table_info = {
            'schema': schema,
            'created_at': self._get_current_time(),
            'record_count': 0,
            'pages': []
        }
        
        # 保存到目录
        self.catalog[table_name] = table_info
        self._save_catalog()
    
    def insert_record(self, table_name: str, record: Dict[str, Any]):
        """插入记录"""
        if table_name not in self.catalog:
            raise ValueError(f"表 '{table_name}' 不存在")
        
        table_info = self.catalog[table_name]
        schema = table_info['schema']
        
        # 序列化记录
        serialized_record = RecordSerializer.serialize_record(record, schema)
        
        # 查找可用的页面
        page_id = self._find_available_page(table_name, len(serialized_record))
        
        # 读取页面数据
        page_data = self.storage.read_page(page_id)
        
        # 在页面中查找空闲位置
        offset = self._find_free_space_in_page(page_data, len(serialized_record))
        
        if offset == -1:
            raise ValueError("页面空间不足")
        
        # 写入记录
        page_data = bytearray(page_data)
        page_data[offset:offset+len(serialized_record)] = serialized_record
        
        # 更新页面头部信息
        self._update_page_header(page_data, offset, len(serialized_record))
        
        # 写回页面
        self.storage.write_page(page_id, bytes(page_data))
        
        # 更新表信息
        table_info['record_count'] += 1
        self._save_catalog()
    
    def query_table(self, table_name: str, conditions: Dict[str, Any] = None) -> List[Dict[str, Any]]:
        """查询表"""
        if table_name not in self.catalog:
            return []
        
        table_info = self.catalog[table_name]
        schema = table_info['schema']
        
        # 获取表的页面
        page_ids = self.storage.get_table_pages(table_name)
        if not page_ids:
            return []
        
        # 读取所有记录
        all_records = []
        for page_id in page_ids:
            page_data = self.storage.read_page(page_id)
            records = self._extract_records_from_page(page_data, schema)
            all_records.extend(records)
        
        # 应用条件过滤
        if conditions:
            filtered_records = []
            for record in all_records:
                if self._match_conditions(record, conditions):
                    filtered_records.append(record)
            return filtered_records
        
        return all_records
    
    def update_record(self, table_name: str, conditions: Dict[str, Any], updates: Dict[str, Any]):
        """更新记录"""
        if table_name not in self.catalog:
            raise ValueError(f"表 '{table_name}' 不存在")
        
        table_info = self.catalog[table_name]
        schema = table_info['schema']
        
        # 获取表的页面
        page_ids = self.storage.get_table_pages(table_name)
        if not page_ids:
            return
        
        updated_count = 0
        
        # 处理每个页面
        for page_id in page_ids:
            page_data = self.storage.read_page(page_id)
            page_data = bytearray(page_data)
            
            # 获取页面中的记录信息
            record_infos = self._get_page_record_infos(page_data)
            
            # 更新记录
            for record_info in record_infos:
                if record_info['deleted']:
                    continue
                
                # 读取记录
                record_data = page_data[record_info['offset']:record_info['offset']+record_info['size']]
                record = RecordSerializer.deserialize_record(record_data, schema)
                
                # 检查条件
                if self._match_conditions(record, conditions):
                    # 更新记录
                    for key, value in updates.items():
                        record[key] = value
                    
                    # 重新序列化记录
                    new_record_data = RecordSerializer.serialize_record(record, schema)
                    
                    # 检查新记录是否能放入原位置
                    if len(new_record_data) <= record_info['size']:
                        # 直接替换
                        page_data[record_info['offset']:record_info['offset']+len(new_record_data)] = new_record_data
                        # 更新记录大小
                        self._update_record_size(page_data, record_info, len(new_record_data))
                    else:
                        # 需要重新分配空间
                        # 标记原记录为删除
                        self._mark_record_deleted(page_data, record_info)
                        # 在页面末尾添加新记录
                        new_offset = self._find_free_space_in_page(page_data, len(new_record_data))
                        if new_offset != -1:
                            page_data[new_offset:new_offset+len(new_record_data)] = new_record_data
                            self._add_record_to_page_header(page_data, new_offset, len(new_record_data))
                    
                    updated_count += 1
            
            # 写回页面
            self.storage.write_page(page_id, bytes(page_data))
        
        return updated_count
    
    def delete_record(self, table_name: str, conditions: Dict[str, Any]):
        """删除记录"""
        if table_name not in self.catalog:
            raise ValueError(f"表 '{table_name}' 不存在")
        
        table_info = self.catalog[table_name]
        schema = table_info['schema']
        
        # 获取表的页面
        page_ids = self.storage.get_table_pages(table_name)
        if not page_ids:
            return 0
        
        deleted_count = 0
        
        # 处理每个页面
        for page_id in page_ids:
            page_data = self.storage.read_page(page_id)
            page_data = bytearray(page_data)
            
            # 获取页面中的记录信息
            record_infos = self._get_page_record_infos(page_data)
            
            # 标记要删除的记录
            for record_info in record_infos:
                if record_info['deleted']:
                    continue
                
                # 读取记录
                record_data = page_data[record_info['offset']:record_info['offset']+record_info['size']]
                record = RecordSerializer.deserialize_record(record_data, schema)
                
                # 检查条件
                if self._match_conditions(record, conditions):
                    self._mark_record_deleted(page_data, record_info)
                    deleted_count += 1
            
            # 写回页面
            self.storage.write_page(page_id, bytes(page_data))
        
        # 更新表信息
        table_info['record_count'] = max(0, table_info['record_count'] - deleted_count)
        self._save_catalog()
        
        return deleted_count
    
    def _find_available_page(self, table_name: str, record_size: int) -> int:
        """查找可用的页面"""
        page_ids = self.storage.get_table_pages(table_name)
        
        # 检查现有页面是否有足够空间
        for page_id in page_ids:
            page_data = self.storage.read_page(page_id)
            if self._has_space_in_page(page_data, record_size):
                return page_id
        
        # 分配新页面
        new_page_id = self.storage.allocate_page()
        self.storage.add_page_to_table(table_name, new_page_id)
        
        # 初始化页面头部
        page_data = bytearray(self.storage.page_size)
        self._initialize_page_header(page_data)
        self.storage.write_page(new_page_id, bytes(page_data))
        
        return new_page_id
    
    def _has_space_in_page(self, page_data: bytes, record_size: int) -> bool:
        """检查页面是否有足够空间"""
        header_size = 64
        used_space = self._get_used_space_in_page(page_data)
        return (len(page_data) - header_size - used_space) >= record_size
    
    def _get_used_space_in_page(self, page_data: bytes) -> int:
        """获取页面中已使用的空间"""
        import struct
        record_count = struct.unpack('<I', page_data[0:4])[0]
        used_space = 0
        
        for i in range(record_count):
            offset = 8 + i * 12
            if offset + 8 <= len(page_data):
                size = struct.unpack('<I', page_data[offset+4:offset+8])[0]
                used_space += size
        
        return used_space
    
    def _find_free_space_in_page(self, page_data: bytes, record_size: int) -> int:
        """在页面中查找空闲空间"""
        header_size = 64
        used_space = self._get_used_space_in_page(page_data)
        
        if (len(page_data) - header_size - used_space) >= record_size:
            return header_size + used_space
        
        return -1
    
    def _initialize_page_header(self, page_data: bytearray):
        """初始化页面头部"""
        import struct
        struct.pack_into('<I', page_data, 0, 0)  # 记录数量
        struct.pack_into('<I', page_data, 4, 1)  # 页面状态
    
    def _update_page_header(self, page_data: bytearray, offset: int, size: int):
        """更新页面头部，添加记录信息"""
        import struct
        record_count = struct.unpack('<I', page_data[0:4])[0]
        
        # 添加新记录信息
        info_offset = 8 + record_count * 12
        struct.pack_into('<I', page_data, info_offset, offset)
        struct.pack_into('<I', page_data, info_offset + 4, size)
        struct.pack_into('<I', page_data, info_offset + 8, 0)  # 0表示未删除
        
        # 更新记录数量
        struct.pack_into('<I', page_data, 0, record_count + 1)
    
    def _get_page_record_infos(self, page_data: bytes) -> List[Dict[str, Any]]:
        """获取页面中的记录信息"""
        import struct
        record_count = struct.unpack('<I', page_data[0:4])[0]
        record_infos = []
        
        for i in range(record_count):
            offset = 8 + i * 12
            if offset + 12 <= len(page_data):
                record_offset = struct.unpack('<I', page_data[offset:offset+4])[0]
                record_size = struct.unpack('<I', page_data[offset+4:offset+8])[0]
                deleted = struct.unpack('<I', page_data[offset+8:offset+12])[0]
                
                record_infos.append({
                    'offset': record_offset,
                    'size': record_size,
                    'deleted': bool(deleted)
                })
        
        return record_infos
    
    def _mark_record_deleted(self, page_data: bytearray, record_info: Dict[str, Any]):
        """标记记录为删除"""
        import struct
        record_count = struct.unpack('<I', page_data[0:4])[0]
        
        for i in range(record_count):
            offset = 8 + i * 12
            if offset + 12 <= len(page_data):
                record_offset = struct.unpack('<I', page_data[offset:offset+4])[0]
                if record_offset == record_info['offset']:
                    struct.pack_into('<I', page_data, offset + 8, 1)  # 1表示已删除
                    break
    
    def _update_record_size(self, page_data: bytearray, record_info: Dict[str, Any], new_size: int):
        """更新记录大小"""
        import struct
        record_count = struct.unpack('<I', page_data[0:4])[0]
        
        for i in range(record_count):
            offset = 8 + i * 12
            if offset + 12 <= len(page_data):
                record_offset = struct.unpack('<I', page_data[offset:offset+4])[0]
                if record_offset == record_info['offset']:
                    struct.pack_into('<I', page_data, offset + 4, new_size)
                    break
    
    def _add_record_to_page_header(self, page_data: bytearray, offset: int, size: int):
        """添加记录到页面头部"""
        self._update_page_header(page_data, offset, size)
    
    def _extract_records_from_page(self, page_data: bytes, schema: Dict[str, Any]) -> List[Dict[str, Any]]:
        """从页面中提取记录"""
        record_infos = self._get_page_record_infos(page_data)
        records = []
        
        for record_info in record_infos:
            if not record_info['deleted']:
                record_data = page_data[record_info['offset']:record_info['offset']+record_info['size']]
                record = RecordSerializer.deserialize_record(record_data, schema)
                records.append(record)
        
        return records
    
    def _match_conditions(self, record: Dict[str, Any], conditions: Dict[str, Any]) -> bool:
        """匹配条件"""
        for key, value in conditions.items():
            if record.get(key) != value:
                return False
        return True
    
    def _get_current_time(self) -> str:
        """获取当前时间字符串"""
        return str(int(time.time()))